#include "Matrix.h"

using namespace std;

//----------------------------------------------------------------------
//CNode Construction and Destruction
//----------------------------------------------------------------------

CNode::CNode()
{
	m_x=-1;
	m_y=-1;
	m_nextNode=NULL;
	
}

CNode::~CNode()
{
}

//----------------------------------------------------------------------
//CHeader Construction and Destruction
//----------------------------------------------------------------------

CHeader::CHeader()
{
	m_node=NULL;
	m_nodeCount=0;
	int ii;
	for (ii=0;ii<MAXNUMDENSITYTYPE;ii++)
		m_nodePixelCount[ii]=0;
}

CHeader::~CHeader()
{
	CNode* temp;
	while (m_node!=NULL)
	{
		temp=m_node->m_nextNode;
		delete m_node;
		m_node=temp;		
	}
}

void CHeader::AddNode()
{
	CNode* temp;
	 
	temp=m_node;
	m_node=new CNode();
	m_node->m_nextNode=temp;
	m_nodeCount++;
}

//----------------------------------------------------------------------
//CMatrix Construction and Destruction
//----------------------------------------------------------------------

CMatrix::CMatrix()
{
	m_matLength=0;
	m_height=m_width=0;
	m_numOrder=0;

	int ii;
	for (ii=0;ii<MAXNUMMATRIXMAP;ii++)
		m_matMap[ii]=NULL;

	m_centerX=m_centerY=-1;

	MakeOrderList();

}

CMatrix::CMatrix(int mapHeight, int mapWidth)
{
	m_matLength=0;
	m_height=m_width=0;
	m_numOrder=0;

	int ii;
	for (ii=0;ii<MAXNUMMATRIXMAP;ii++)
		m_matMap[ii]=NULL;

	m_centerX=m_centerY=-1;

	m_height=mapHeight;
	m_width=mapWidth;

	MakeOrderList();

}

CMatrix::~CMatrix()
{
	//Remove the temprary array
	int ii;
	for (ii=0;ii<MAXNUMMATRIXMAP;ii++)
		if (m_matMap[ii]!=NULL) DeleteMatrixMap(m_matMap[ii]);
//	if (m_matMap[ISOTROPIC]!=NULL) DeleteMatrixMap(m_matMap[ISOTROPIC]);
//	if (m_matMap[HORIZONTAL]!=NULL) DeleteMatrixMap(m_matMap[HORIZONTAL]);
//	if (m_matMap[VERTICAL]!=NULL) DeleteMatrixMap(m_matMap[VERTICAL]);
/*	{
		for (ii=0;ii<m_matLength; ii++) delete mat[ii];
		delete mat;
	}
*/
	//cout<<"The matrix is terminated."<<endl;
}

int* CMatrix::GetOrderList()
{
	return m_orderArray;
}

int CMatrix::GetNumOrder()
{
	return m_numOrder;
}

void CMatrix::SetMapSize(int mapHeight, int mapWidth)
{
	m_height=mapHeight;
	m_width=mapWidth;
}


int* CMatrix::MakeOrderList()
{

	int ii=0;
	int maxOrder, minOrder, orderInterval;
	int tempOrder;

	#ifdef ADV_OPTIONS
	
	cout<<"Input a Max. order (pixels) : ";
	cin>>maxOrder;
	
	cout<<"Input a Min. order (pixels) : ";
	cin>>minOrder;

	cout<<"Input an order interval (pixels) : ";
	cin>>orderInterval;
	cout<<endl;
	
	#endif
	
	#ifndef ADV_OPTIONS
	
	if (m_height>m_width) maxOrder=(int)(m_height/2);
	else maxOrder=(int)(m_width/2);
	
	minOrder=(int)(maxOrder*0.1);
	
	orderInterval=minOrder;
	
	#endif

	cout<<" Order List (radius of each matrix) : ";

	tempOrder=maxOrder;
	while (tempOrder>=minOrder)
	{
		m_orderArray[ii]=tempOrder;
		tempOrder=tempOrder-orderInterval;
		cout<<m_orderArray[ii]<<" ";
		ii++;
	}
	
	m_orderArray[ii]=-1;
	cout<<endl;
	cout<<" The number of the order : "<<ii<<endl;
	cout<<endl;

	m_matLength=2*(2*m_orderArray[0])+1;
	m_centerX=m_centerY=2*m_orderArray[0]+1;

	//Conuting of the order
	m_numOrder=0;
	while (m_orderArray[m_numOrder]>0) m_numOrder++;

	return m_orderArray;
}

INDEXMAP CMatrix::MatrixType(int matType, char* strMatType)
{
	INDEXMAP tempMap;
	char tempType[256];
	
	switch(matType)
	{
		case ISOTROPIC : 
			{
				if (m_matMap[matType]==NULL)
				{ 
					tempMap=MakeMatrixMap(matType);
					
				}
				else
					tempMap=m_matMap[matType];
				strcpy(tempType,"iso");
			}
			break;
		case HORIZONTAL :
			{
				if (m_matMap[matType]==NULL)
				{ 
					tempMap=MakeMatrixMap(matType);
				}
				else
					tempMap=m_matMap[matType];
				strcpy(tempType,"hor");
			}
			break;
		case VERTICAL :
			{
				if (m_matMap[matType]==NULL)
				{ 
					tempMap=MakeMatrixMap(matType);
				}
				else
					tempMap=m_matMap[matType];
				strcpy(tempType,"ver");
			}
			break;
		case SQUARE :
			{
				if (m_matMap[matType]==NULL)
				{ 
					tempMap=MakeMatrixMap(matType);
				}
				else
					tempMap=m_matMap[matType];
				strcpy(tempType,"sqr");
			}
			break;
		default :
			{ 
				cout<<"There is no predefined matrix map type."<<endl;
				if ((m_matMap[matType]==NULL)||(matType>=MAXNUMMATRIXMAP))
				{ 
					cout<<"Error: The type number, "<<matType<<" is unknown."<<endl;
					exit(0);
				}
				else
				{
					tempMap=m_matMap[matType];
					strcpy(tempType,"unknown");
				}
			}
	}

	if (strMatType!=NULL) strcpy(strMatType,tempType);
	
	if (tempMap==NULL) cout<<"CAUTION: The "<<strMatType<<" matrix is NULL data."<<endl;
	
	return tempMap;
}

INDEXMAP CMatrix::MakeNULLMatrixMap()
{
	int ii, jj;
	
	INDEXMAP map;
	
	map= new int* [m_matLength];
	for (ii=0;ii<m_matLength; ii++)
		map[ii]= new int [m_matLength];

	for (ii=0;ii<m_matLength; ii++)
		for (jj=0;jj<m_matLength; jj++)
			map[ii][jj]=NODATA;
	
	return map;
}

void CMatrix::DeleteMatrixMap(INDEXMAP map)
{
	int ii;
	
	if (map!=NULL)
	{
		for (ii=0;ii<m_matLength; ii++) delete map[ii];
		delete map;
	}
}

CHeader* CMatrix::MakeMatrixList(INDEXMAP map)
{
	int ii, jj;
	
	CHeader* matHeader=new CHeader[m_numOrder];
	
	for(ii=0;ii<m_matLength;ii++)
		for(jj=0;jj<m_matLength;jj++)
			if (map[ii][jj]!=-9999)
			{
				matHeader[map[ii][jj]].AddNode();
				matHeader[map[ii][jj]].m_node->m_x=ii-m_centerX; 
				matHeader[map[ii][jj]].m_node->m_y=jj-m_centerY;
			}
			
	for (ii=m_numOrder-1;ii>0;ii--)
		matHeader[ii-1].m_nodeCount+=matHeader[ii].m_nodeCount;
	
	return matHeader;
}

void CMatrix::DeleteMatrixList(CHeader* matList)
{

	if (matList!=NULL) delete[] matList;

}

INDEXMAP CMatrix::MakeMatrixMap(int matType)
{
	int ii, jj, loop;
	double radius, dist1, dist2;
	
	INDEXMAP matrixMap=MakeNULLMatrixMap();
	
	switch(matType)
	{
		case ISOTROPIC : 
			{
				for(loop=0;loop<m_numOrder;loop++)
				{
					radius=m_orderArray[loop]+0.5;
					for(ii=0;ii<m_matLength;ii++)
						for (jj=0;jj<m_matLength;jj++)
						{
							dist1=pow((-(m_centerX)+ii),2.0)+pow((-(m_centerY)+jj),2.0);
							dist2=pow(radius,2.0);
							if (dist1<=dist2) matrixMap[ii][jj]=loop;
						}
				}
			}
			break;
		case HORIZONTAL : 
			{
				for(loop=0;loop<m_numOrder;loop++)
				{
					radius=m_orderArray[loop]+0.5;
					for(ii=0;ii<m_matLength;ii++)
						for (jj=0;jj<m_matLength;jj++)
						{
							dist1=pow((-(m_centerX)+ii),2.0)+4*pow((-(m_centerY)+jj),2.0);
							dist2=2*pow(radius,2.0);
							if (dist1<=dist2) matrixMap[ii][jj]=loop;
						}
				}
			}
			break;
		case VERTICAL : 
			{
				for(loop=0;loop<m_numOrder;loop++)
				{
					radius=m_orderArray[loop]+0.5;
					for(ii=0;ii<m_matLength;ii++)
						for (jj=0;jj<m_matLength;jj++)
						{
							dist1=4*pow((-(m_centerX)+ii),2.0)+pow((-(m_centerY)+jj),2.0);
							dist2=2*pow(radius,2.0);
							if (dist1<=dist2) matrixMap[ii][jj]=loop;
						}
				}
			}
			break;
		case SQUARE : 
			{
				for(loop=0;loop<m_numOrder;loop++)
				{
					radius=m_orderArray[loop];
					for(ii=0;ii<m_matLength;ii++)
						for (jj=0;jj<m_matLength;jj++)
						{
							if (((-(m_centerX)+ii)<=radius)&&((-(m_centerX)+ii)>=-radius))
								if (((-(m_centerY)+jj)<=radius)&&((-(m_centerY)+jj)>=-radius))
									matrixMap[ii][jj]=loop;
						}
				}
			}
			break;
		default :
			{
				cout<<"There is no predefined matrix map type."<<endl;
				cout<<"Error: The type number, "<<matType<<" is unknown."<<endl;
				exit(0);
			}
	} 
	
	m_matMap[matType]=matrixMap;
	
	return matrixMap;
		
}
/*
INDEXMAP CMatrix::MakeMatrixMap(int matType)
{
	int ii, jj, loop;
	double dist1, dist2;
	//CHeader* matList;
	
	INDEXMAP matrixMap=MakeNULLMatrixMap();
	
	if (matType==ISOTROPIC)
	{
		for(loop=0;loop<m_numOrder;loop++)
		{
			for(ii=0;ii<m_matLength;ii++)
				for (jj=0;jj<m_matLength;jj++)
				{
					dist1=pow((-(m_centerX)+ii),2.0)+pow((-(m_centerY)+jj),2.0);
					dist2=pow((m_orderArray[loop]),2.0);
					if (dist1<=dist2) matrixMap[ii][jj]=loop;
				}
		}
	}

	if (matType==HORIZONTAL)
	{
		for(loop=0;loop<m_numOrder;loop++)
		{
			for(ii=0;ii<m_matLength;ii++)
				for (jj=0;jj<m_matLength;jj++)
				{
					dist1=pow((-(m_centerX)+ii),2.0)+4*pow((-(m_centerY)+jj),2.0);
					dist2=2*pow((m_orderArray[loop]),2.0);
					if (dist1<=dist2) matrixMap[ii][jj]=loop;
				}
		}
	}
	
	if (matType==VERTICAL)
	{
		for(loop=0;loop<m_numOrder;loop++)
		{
			for(ii=0;ii<m_matLength;ii++)
				for (jj=0;jj<m_matLength;jj++)
				{
					dist1=4*pow((-(m_centerX)+ii),2.0)+pow((-(m_centerY)+jj),2.0);
					dist2=2*pow((m_orderArray[loop]),2.0);
					if (dist1<=dist2) matrixMap[ii][jj]=loop;
				}
		}
	}

	//matList=MakeMatrixList(matrixMap);
	
	m_matMap[matType]=matrixMap;
	//isoList=matList;
	
	return matrixMap;

}
*/
/*
INDEXMAP CMatrix::MakeHorizontalMatrix()
{
	int ii, jj, loop;
	double dist1, dist2;
	//CHeader* matList;
	
	INDEXMAP matrixMap=MakeMatrixMap();
	

	//matList=MakeMatrixList(matrixMap);
	
	m_matMap[HORIZONTAL]=matrixMap;
	//horList=matList;
	
	return matrixMap;

}

INDEXMAP CMatrix::MakeVerticalMatrix()
{
		int ii, jj, loop;
	double dist1, dist2;
//	CHeader* matList;
	
	INDEXMAP matrixMap=MakeMatrixMap();
	

	//matList=MakeMatrixList(matrixMap);
	
	m_matMap[VERTICAL]=matrixMap;
	//verList=matList;
	
	return matrixMap;

}*/

void CMatrix::PrintASCIIMatrix(int matType)
{
	int ii, jj;
	char mn1[256], strMatType[256];

	INDEXMAP XY=MatrixType(matType, strMatType);

	strcpy(mn1,strMatType);
	strcat(mn1,"_");
	strcat(mn1,"matrix.asc");
	
	ofstream f1;
	
	f1.open(mn1);

	f1<<"ncols"<<"\t"<<m_matLength<<endl;
	f1<<"nrows"<<"\t"<<m_matLength<<endl;
	f1<<"xllcorner"<<"\t"<<0<<endl;
	f1<<"yllcorner"<<"\t"<<0<<endl;
	f1<<"cellsize"<<"\t"<<1<<endl;
	f1<<"NODATA_value"<<"\t"<<NODATA<<endl;

	for (jj=0; jj<m_matLength; jj++) 
	{
		for (ii=0; ii<m_matLength; ii++)
			f1<<XY[ii][jj]<<"\t";

		f1<<endl;
	}

	f1.close();
}

void CMatrix::Print2DList(int matType)
{
	int ii, jj;
	char mn1[256], strMatType[256];

	INDEXMAP XY=MatrixType(matType, strMatType);

	strcpy(mn1,strMatType);
	strcat(mn1,"_");
	strcat(mn1,"matrix.txt");
	
	ofstream f1;
	
	f1.open(mn1);

	for (jj=m_matLength-1; jj>-1; jj--) 
	{
		for (ii=0; ii<m_matLength; ii++)
			f1<<XY[ii][jj]<<"\t";

		f1<<endl;
	}

	f1.close();
}
/*
void CMatrix::PrintMatrixList(int matType)
{
	int ii;
	CHeader* tempList=NULL;
	CNode* tempNode;
	char mn1[256], strMatType[256];

	MatrixType(matType, strMatType);
	
	if (matType==ISOTROPIC) tempList=isoList;
	if (matType==HORIZONTAL) tempList=horList;
	if (matType==VERTICAL) tempList=verList;
	

	strcpy(mn1,strMatType);
	strcat(mn1,"_");
	strcpy(mn1,"matrix_List.txt");
	ofstream f1;
	f1.open(mn1);
	
	f1<<"Order\tX\tY"<<endl;
	
	for (ii=0;ii<m_numOrder;ii++)
	{
		tempNode=tempList[ii].m_node;
		while (tempNode!=NULL)
		{
			f1<<ii<<"\t"<<tempNode->m_x<<"\t"<<tempNode->m_y<<endl;
			tempNode=tempNode->m_nextNode;
		}
	}
	
	f1.close();
}
*/

